This example mirrors modulate.ipynb.
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"FA.nii.gz",
"V1.nii.gz",
],
)
FA.nii.gz already exists. V1.nii.gz already exists. Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets
from IPython.display import display
import ipyniivue
nv = ipyniivue.NiiVue()
# Set options
nv.opts.back_color = (0.0, 0.0, 0.2, 1.0)
nv.opts.show_3d_crosshair = True
nv.opts.drag_mode = ipyniivue.DragMode.PAN
nv.opts.yoke_3d_to_2d_zoom = True
nv.opts.crosshair_width = 0.1
nv.opts.is_force_mouse_click_to_voxel_centers = True
nv.opts.is_nearest_interpolation = True
nv.scene.crosshair_pos = [0.51, 0.51, 0.51]
# Create Volumes
vol_fa = ipyniivue.Volume(path=DATA_FOLDER / "FA.nii.gz", opacity=1.0)
vol_v1 = ipyniivue.Volume(path=DATA_FOLDER / "V1.nii.gz", opacity=1.0)
# Load volumes
nv.load_volumes([vol_fa, vol_v1])
# --- UI Controls ---
mode_dropdown = widgets.Dropdown(
options=["FA", "V1", "V1 modulated by FA", "Lines", "Lines modulated by FA"],
value="Lines modulated by FA",
description="Display:",
style={"description_width": "initial"},
)
slider_min = widgets.FloatSlider(
min=0, max=1.0, step=0.01, value=0.0, description="FAmin", continuous_update=True
)
slider_max = widgets.FloatSlider(
min=0, max=1.0, step=0.01, value=1.0, description="FAmax", continuous_update=True
)
check_clip = widgets.Checkbox(value=True, description="ClipDark")
location_label = widgets.Label(value="Location: ")
# --- Callbacks ---
def update_view(change=None):
"""Update view."""
mode = mode_dropdown.value
# Opacity Handling
if mode == "FA": # Index 0
vol_fa.opacity = 1.0
vol_v1.opacity = 0.0
elif mode in ["Lines", "Lines modulated by FA"]: # Index 3, 4
vol_fa.opacity = 1.0
vol_v1.opacity = 1.0
else: # V1, V1 modulated by FA (Index 1, 2)
vol_fa.opacity = 0.0
vol_v1.opacity = 1.0
# Modulation Handling
# Modes 2 and 4 use modulation
if mode in ["V1 modulated by FA", "Lines modulated by FA"]:
nv.set_modulation_image(vol_v1.id, vol_fa.id)
else:
nv.set_modulation_image(vol_v1.id, "")
# Shader Handling
# Modes 3 and 4 use V1SliceShader
nv.opts.is_v1_slice_shader = mode in ["Lines", "Lines modulated by FA"]
def update_contrast(change=None):
"""Update contrast."""
mn = slider_min.value
mx = slider_max.value
vol_fa.cal_min = min(mn, mx)
vol_fa.cal_max = max(mn, mx)
def update_clip(change=None):
"""Update clip dark."""
nv.opts.is_alpha_clip_dark = check_clip.value
def on_location_change(data):
"""Update location string."""
if "string" in data:
location_label.value = "Location: " + data["string"]
# --- Bind Events ---
mode_dropdown.observe(update_view, names="value")
slider_min.observe(update_contrast, names="value")
slider_max.observe(update_contrast, names="value")
check_clip.observe(update_clip, names="value")
nv.on_location_change(on_location_change)
# --- Initialization ---
update_clip()
nv.on_canvas_attached(update_view)
# --- Layout and Display ---
ui = widgets.VBox(
[
widgets.HBox([mode_dropdown, check_clip]),
widgets.HBox([slider_min, slider_max]),
nv,
location_label,
]
)
display(ui)